package main

import (
	"fmt"
	"net"
	"strings"
	"time"
)

var message = make(chan string)

//处理客户端请求
func handerConnect(con net.Conn) {
	defer con.Close() //关闭连接
	fmt.Println("开始处理客户端请求-------")
	remoteAddr := con.RemoteAddr().String()
	//初始化client
	client := Client{
		Name: remoteAddr,
		Addr: remoteAddr,
		C:    make(chan string), //初始化信道
	}
	isQuit := make(chan bool)
	hasData := make(chan bool)
	//添加对象到在线的消息对象
	addClient(remoteAddr, client)
	//为每个客户端发送消息
	go WriteMsg2Client(con, client)
	fmt.Println("往全局对象写入数据------")
	message <- makeMsg(client, "login")
	go func() { //处理客户端的消息
		buf := make([]byte, 4096)
		for {
			n, err := con.Read(buf)
			if n == 0 {
				fmt.Println("读取完客户端消息------")
				isQuit <- true //假如没有获取到客户端的消息那么退出
				return
			}
			if err != nil {
				fmt.Println("读取客户端消息失败")
				return
			}
			msg := string(buf[:n])
			if msg == "who" && len(msg) == 3 {
				con.Write([]byte("user list:\n"))
				for _, user := range onlineMap {
					userInfo := user.Addr + ":" + user.Name + "\n"
					con.Write([]byte(userInfo))
				}
			} else if len(msg) >= 8 && msg[:6] == "rename" { // rename | Iron man
				newName := strings.Split(msg, "|")[1] // 按"|"拆分，rename为[0], Iron man为[1]
				client.Name = newName                 // 替换掉当前用户原始Name
				onlineMap[remoteAddr] = client        // 使用netAddr为key找到map中当前用户。覆盖
				con.Write([]byte("rename successful\n"))
			} else {
				message <- makeMsg(client, msg) //广播客户端发送的消息
			}
			hasData <- true
		}

	}()
	for {
		select {
		case <-isQuit:
			delete(onlineMap, remoteAddr)
			message <- makeMsg(client, "退出")
			return
		case <-hasData:
		// 什么都不做。 目的是重置 下面 case 的计时器。
		case <-time.After(time.Second * 60):
			delete(onlineMap, client.Addr)
			message <- makeMsg(client, "超时踢出")
			return
		}
	}
}

//聊天室
func main() {
	lis, err := net.Listen("tcp", "127.0.0.1:8000")
	if err != nil {
		fmt.Println("监听端口号和地址出错了", err)
		return
	}
	defer lis.Close()
	fmt.Println("启动服务器监听成功了--------")
	//初始化map并且监听全局消息
	go Manager()
	for {
		conn, err := lis.Accept()
		if err != nil {
			fmt.Println("获取客户端连接失败了------")
		}
		go handerConnect(conn)
	}

}

// Client client 端
type Client struct {
	C    chan string
	Name string
	Addr string
}

// WriteMsg2Client 发送消息给客户端
func WriteMsg2Client(con net.Conn, client Client) {
	//阻塞监听C的消息，假如有那么发送给客户端
	for {
		msg := <-client.C
		_, err := con.Write([]byte(msg))
		if err != nil {
			fmt.Println("发送消息给客户端失败了------", err)
		}
		fmt.Println("消息发送成功--------")
	}
}

//manager 管理
var onlineMap map[string]Client

func makeMsg(client Client, str string) string {
	return "[" + client.Addr + "]" + client.Name + "|" + str + "\n"
}

//初始化map
func initMap() {
	onlineMap = make(map[string]Client)
}

func addClient(addr string, client Client) {
	onlineMap[addr] = client
}

func Manager() {
	initMap()
	for { //监听全局消息,不断的监听
		msg := <-message
		fmt.Println("接收到全局消息-------,当前客户端个数为：", len(onlineMap))
		for _, cli := range onlineMap {
			cli.C <- msg
		}
	}
}
